package cn.com.shadowless.xinning.net;

import com.google.gson.GsonBuilder;

import java.io.EOFException;
import java.net.ConnectException;
import java.net.SocketException;
import java.net.SocketTimeoutException;
import java.net.UnknownHostException;
import java.util.concurrent.TimeUnit;

import cn.com.shadowless.xinning.api.Bill;
import cn.com.shadowless.xinning.api.Order;
import cn.com.shadowless.xinning.api.Login;
import cn.com.shadowless.xinning.utils.Constants;
import io.reactivex.ObservableTransformer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.schedulers.Schedulers;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import retrofit2.converter.gson.GsonConverterFactory;

/**
 * The type Http methods.
 *
 * @author sHadowLess
 */
public class HttpMethods {

    private static volatile OkHttpClient okHttpClient;

    /**
     * 根地址
     */
    protected final String BASE_URL = Constants.BASE_URL;
    /**
     * The Default timeout.
     */
    protected final int DEFAULT_TIMEOUT = 30;

    /**
     * The constant mInstance.
     */
    protected volatile static HttpMethods mInstance;

    /**
     * 获取实例对象
     */
    public static void getInstance() {
        if (mInstance == null) {
            synchronized (HttpMethods.class) {
                if (mInstance == null) {
                    mInstance = new HttpMethods();
                }
            }
        }
    }

    /**
     * The constant loginService.
     */
    protected static Login login;
    /**
     * The constant bill.
     */
    protected static Bill bill;
    /**
     * The constant order.
     */
    protected static Order order;

    /**
     * 构造方法
     */
    public HttpMethods() {
        if (mInstance == null) {
            Retrofit retrofit = new Retrofit.Builder()
                    .baseUrl(BASE_URL)
                    .addConverterFactory(GsonConverterFactory.create(new GsonBuilder().setLenient().create()))
                    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                    .client(getOkHttpClient())
                    .build();
            //初始化接口
            login = retrofit.create(Login.class);
            bill = retrofit.create(Bill.class);
            order = retrofit.create(Order.class);
        }
    }

    /**
     * Obs io main observable transformer.
     *
     * @param <T> the type parameter
     * @return the observable transformer
     */
    public <T> ObservableTransformer<T, T> obsIoMain() {
        return upstream -> upstream.subscribeOn(Schedulers.io())
                .unsubscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread());
    }

    /**
     * Gets ok http client.
     *
     * @return the ok http client
     */
    public OkHttpClient getOkHttpClient() {
        if (okHttpClient == null) {
            synchronized (HttpMethods.class) {
                okHttpClient = new OkHttpClient.Builder()
                        .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                        .readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                        .writeTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS)
                        .hostnameVerifier((s, sslSession) -> true)
                        .build();
            }
        }
        return okHttpClient;
    }

    /**
     * Check exception constants . error.
     *
     * @param e the e
     * @return the constants . error
     */
    public Constants.ERROR checkException(Throwable e) {
        if (e instanceof SocketTimeoutException) {
            return Constants.ERROR.TIMEOUT;
        } else if (e instanceof ConnectException) {
            return Constants.ERROR.CONNECT_REFUSED;
        } else if (e instanceof SocketException) {
            return Constants.ERROR.SOCKET_CLOSED;
        } else if (e instanceof EOFException) {
            return Constants.ERROR.WAVE;
        } else if (e instanceof UnknownHostException) {
            return Constants.ERROR.UN_KNOW_HOST;
        } else {
            return Constants.ERROR.DEFAULT;
        }
    }

    /**
     * Exception message string.
     *
     * @param error the error
     * @return the string
     */
    public String exceptionMessage(Constants.ERROR error) {
        switch (error) {
            case UN_KNOW_HOST:
                return Constants.ERROR_UN_KNOW_HOST_MESSAGE;
            case TIMEOUT:
                return Constants.ERROR_TIME_OUT_MESSAGE;
            case SOCKET_CLOSED:
                return Constants.ERROR_SOCKET_CLOSED_MESSAGE;
            case CONNECT_REFUSED:
                return Constants.ERROR_CONNECT_REFUSED_MESSAGE;
            case WAVE:
                return Constants.ERROR_WAVE_MESSAGE;
            default:
                return Constants.ERROR_DEFAULT;
        }
    }
}
